//  这句话用来编程时自动提示，运行时需要注释掉！
//import * as BABYLON from '@babylonjs/core';

var canvas = document.getElementById("renderCanvas");

var startRenderLoop = function (engine, canvas) {
  engine.runRenderLoop(function () {
    if (sceneToRender && sceneToRender.activeCamera) {
      sceneToRender.render();
    }
  });
};

var engine = null;
var scene = null;
var sceneToRender = null;
var createDefaultEngine = function () {
  return new BABYLON.Engine(canvas, true, {
    preserveDrawingBuffer: true,
    stencil: true,
    disableWebGL2Support: false,
  });
};

//  通过高度图创建地形
//  创建场景（相关代码都在此处）
var createScene = function () {
  // This creates a basic Babylon Scene object (non-mesh)
  var scene = new BABYLON.Scene(engine);

  //  创建相机
  var camera = new BABYLON.ArcRotateCamera("camera", 0, 1.2, 5, BABYLON.Vector3.Zero());
  camera.attachControl(canvas, true);

  camera.upperBetaLimit = Math.PI / 2.2;

  //  创建灯光
  var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
  light.intensity = 0.1;

  //  显示坐标轴
  showAxis(10, scene);

  // 创建高度图
  const largeGround = BABYLON.MeshBuilder.CreateGroundFromHeightMap("largeGround",
    "https://assets.babylonjs.com/environments/villageheightmap.png", {
    width: 150, height: 150, subdivisions: 100, minHeight: 0, maxHeight: 10
  });

  const largeGroundMaterial = new BABYLON.StandardMaterial("largeGroundMaterial");
  largeGroundMaterial.diffuseTexture = new BABYLON.Texture("https://assets.babylonjs.com/environments/valleygrass.png");
  largeGround.material = largeGroundMaterial;
  largeGround.position.y = -0.1;

  //  创建地面材质(图片)
  const groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
  groundMaterial.diffuseTexture = new BABYLON.Texture("https://assets.babylonjs.com/environments/villagegreen.png", scene);

  //  创建地面
  const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 24, height: 24 }, scene);
  ground.material = groundMaterial;

  //  导入村庄
  BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "valleyvillage.glb");

  //  创建skybox
  const skybox = BABYLON.MeshBuilder.CreateBox("skybox", { size: 150 }, scene);
  const skyboxMaterial = new BABYLON.StandardMaterial("skyboxMaterial", scene);
  skyboxMaterial.backFaceCulling = false; //  关闭背面剔除
  //  立方盒子纹理(使用cubeTexture)（使用在线地址）
  //skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("Skybox/SkyCube2k/skyCube2k", scene);
  skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("https://playground.babylonjs.com/textures/skybox", scene);
  skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
  skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
  skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
  skybox.material = skyboxMaterial;

  //  spirit tree
  const spriteManagerTrees = new BABYLON.SpriteManager("treesManager", "https://playground.babylonjs.com/textures/palm.png",
    2000, { width: 512, height: 1024 }, scene);

  //  在x轴左侧创建500棵树
  for (let i = 0; i < 500; i++) {
    //  创建精灵, 并添加到精灵管理器中
    const tree = new BABYLON.Sprite("tree" + i, spriteManagerTrees);
    tree.position.x = Math.random() * (-30);
    tree.position.z = Math.random() * 20 + 8;
    tree.position.y = 0.5;
  }
  //  在x轴右侧创建500棵树
  for (let i = 0; i < 500; i++) {
    const tree = new BABYLON.Sprite("tree" + i, spriteManagerTrees);
    tree.position.x = Math.random() * 25 + 7;
    tree.position.z = Math.random() * -35 + 8;
    tree.position.y = 0.5;
  }


  //  创建喷泉（通过lathe创建，lathe是创建旋转体）
  const fountainProfile = [
    new BABYLON.Vector3(0, 0, 0),
    new BABYLON.Vector3(10, 0, 0),
    new BABYLON.Vector3(10, 4, 0),
    new BABYLON.Vector3(8, 4, 0),
    new BABYLON.Vector3(8, 1, 0),
    new BABYLON.Vector3(1, 2, 0),
    new BABYLON.Vector3(1, 15, 0),
    new BABYLON.Vector3(3, 17, 0)
  ];

  const fountain = BABYLON.MeshBuilder.CreateLathe("fountain",
    { shape: fountainProfile, sideOrientation: BABYLON.Mesh.DOUBLESIDE }, scene);
  fountain.scaling = new BABYLON.Vector3(0.05, 0.05, 0.05);
  fountain.position = new BABYLON.Vector3(-5, 0, -5);

  //  粒子系统
  const particleSystem = new BABYLON.ParticleSystem("particles", 5000, scene);
  particleSystem.particleTexture = new BABYLON.Texture("https://playground.babylonjs.com/textures/flare.png", scene);
  particleSystem.emitter = new BABYLON.Vector3(-5, 1, -5);
  particleSystem.minEmitBox = new BABYLON.Vector3(-0.1, 0, 0);
  particleSystem.maxEmitBox = new BABYLON.Vector3(0.1, 0, 0);
  particleSystem.color1 = new BABYLON.Color4(1, 0, 0, 1);
  particleSystem.color2 = new BABYLON.Color4(0, 1, 0, 1);
  particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
  particleSystem.minSize = 0.1;
  particleSystem.maxSize = 0.3;
  particleSystem.minLifeTime = 2;
  particleSystem.maxLifeTime = 4;
  particleSystem.emitRate = 1500;
  particleSystem.direction1 = new BABYLON.Vector3(-2, 8, 2);
  particleSystem.direction2 = new BABYLON.Vector3(2, 8, -2);
  particleSystem.minEmitPower = 1;
  particleSystem.maxEmitPower = 3;
  particleSystem.updateSpeed = 0.025;
  particleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);
  particleSystem.start();


  //================================================================================================
  let swithed = false;

  //  点击喷泉开关
  const pointerDown = (mesh) => {
    if (mesh === fountain) {
      swithed = !swithed;
      if (swithed) {
        particleSystem.start();
      }
      else {
        particleSystem.stop();
      }
    }
  };

  scene.onPointerObservable.add((pointerInfo) => {
    switch (pointerInfo.type) {
      case BABYLON.PointerEventTypes.POINTERDOWN:
        if (pointerInfo.pickInfo.hit) {
          pointerDown(pointerInfo.pickInfo.pickedMesh);
        }
        break;
    }
  });

  //  创建路灯(使用ExtrudeShape创建,某一个形状沿着路径创建)
  //================================================================================================
  const lampShape = [];
  for (let i = 0; i < 20; i++) {
    lampShape.push(new BABYLON.Vector3(Math.cos(i * Math.PI / 10), Math.sin(i * Math.PI / 10), 0));
  }
  lampShape.push(lampShape[0]); //  闭合

  const lampPath = [];
  lampPath.push(new BABYLON.Vector3(0, 0, 0));
  lampPath.push(new BABYLON.Vector3(0, 10, 0));
  for (let i = 0; i < 20; i++) {
    lampPath.push(new BABYLON.Vector3(1 + Math.cos(Math.PI - i * Math.PI / 40),
      10 + Math.sin(Math.PI - i * Math.PI / 40), 0));
  }
  lampPath.push(new BABYLON.Vector3(3, 11, 0));

  const lamp = BABYLON.MeshBuilder.ExtrudeShape("lamp",
    { path: lampPath, shape: lampShape, cap: BABYLON.Mesh.CAP_END, scale: 0.5 }, scene);

  // 灯泡
  const bulb = BABYLON.MeshBuilder.CreateSphere("bulb", { diameterX: 1.5, diameterZ: 0.8 }, scene);
  bulb.parent = lamp;
  bulb.position.y = 10.5;
  bulb.position.x = 2;
  bulb.material = new BABYLON.StandardMaterial("bulbMat", scene);
  bulb.material.emissiveColor = BABYLON.Color3.Yellow();
  //================================================================================================
  //  创建灯光
  const lampLight = new BABYLON.SpotLight("lampLight", new BABYLON.Vector3.Zero(),
    new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 0.2, scene);
  lampLight.parent = bulb;

  lamp.scaling = new BABYLON.Vector3(0.1, 0.1, 0.1);


  return scene;
};




//  创建文字平面
const makeTextPlane = (text, color, size) => {
  const dynamicTexture = new BABYLON.DynamicTexture("dynamicTexture", 50, scene, true);
  dynamicTexture.hasAlpha = true;
  dynamicTexture.drawText(text, 5, 40, "bold 36px Arial", color, "transparent", true);

  const plane = BABYLON.MeshBuilder.CreatePlane("plane", { size: size, updatable: true }, scene);
  plane.material = new BABYLON.StandardMaterial("planeMat", scene);
  plane.material.backFaceCulling = false;
  plane.material.specularColor = new BABYLON.Color3(0, 0, 0);
  plane.material.diffuseTexture = dynamicTexture;
  return plane;
}

const showAxis = (length, scene) => {

  //  创建坐标轴x
  const xAxis = BABYLON.MeshBuilder.CreateLines("xAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, 0.1, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, -0.1, 0)]
    }, scene);
  xAxis.color = new BABYLON.Color3(1, 0, 0);
  const xText = makeTextPlane("X", "red", length / 10.0);
  xText.position = new BABYLON.Vector3(length * 0.95, -0.05 * length, 0);

  //  创建坐标轴y
  const yAxis = BABYLON.MeshBuilder.CreateLines("yAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(-0.1, length * 0.95, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(0.1, length * 0.95, 0)]
    }, scene);
  yAxis.color = new BABYLON.Color3(0, 1, 0);
  const yText = makeTextPlane("Y", "green", length / 10.0);
  yText.position = new BABYLON.Vector3(0.05 * length, length * 0.95, 0);

  //  创建坐标轴z
  const zAxis = BABYLON.MeshBuilder.CreateLines("zAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, -0.1, length * 0.95), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, 0.1, length * 0.95)]
    }, scene);
  zAxis.color = new BABYLON.Color3(0, 0, 1);
  const zText = makeTextPlane("Z", "blue", length / 10.0);
  zText.position = new BABYLON.Vector3(0.05 * length, 0.05 * length, length * 0.95);
}


//================================================

window.initFunction = async function () {
  var asyncEngineCreation = async function () {
    try {
      return createDefaultEngine();
    } catch (e) {
      console.log(
        "the available createEngine function failed. Creating the default engine instead"
      );
      return createDefaultEngine();
    }
  };

  window.engine = await asyncEngineCreation();
  if (!engine) throw "engine should not be null.";
  startRenderLoop(engine, canvas);
  window.scene = createScene();
};
initFunction().then(() => {
  sceneToRender = scene;
});

// Resize
window.addEventListener("resize", function () {
  engine.resize();
});